﻿using System;
using System.IO;
using System.Linq;

namespace Flagwind.Expressions.Tokenization
{
	public abstract class LiteralTokenizerBase : ITokenizer
	{
		#region 成员字段

		private bool _ignoreCase;
		private string[] _literals;

		#endregion

		#region 构造方法

		protected LiteralTokenizerBase(params string[] literals) : this(false, literals)
		{
		}

		protected LiteralTokenizerBase(bool ignoreCase, params string[] literals)
		{
			if(literals == null)
				throw new ArgumentNullException(nameof(literals));

			_ignoreCase = ignoreCase;
			_literals = literals;
		}

		#endregion

		#region 保护属性

		protected bool IgnoreCase
		{
			get
			{
				return _ignoreCase;
			}
		}

		protected string[] Literals
		{
			get
			{
				return _literals;
			}
			set
			{
				if(value == null)
					throw new ArgumentNullException();

				_literals = value;
			}
		}

		#endregion

		#region 公共方法

		public TokenResult Tokenize(TextReader reader)
		{
			var literal = string.Empty;
			var valueRead = 0;

			while((valueRead = reader.Read()) > 0)
			{
				var chr = (char)valueRead;

				if(char.IsWhiteSpace(chr))
				{
					if(string.IsNullOrEmpty(literal))
						return TokenResult.Fail(0);

					return new TokenResult(0, this.CreateToken(literal));
				}

				if(!this.Literals.Any(p => p.StartsWith(literal + chr, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)))
				{
					if(this.Literals.Any(p => string.Equals(p, literal, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)))
						return new TokenResult(-1, this.CreateToken(literal));
					else
						return TokenResult.Fail(-(literal.Length + 1));
				}

				literal += chr;
			}

			if(string.IsNullOrEmpty(literal))
				return TokenResult.Fail(0);
			else
				return new TokenResult(0, this.CreateToken(literal));
		}

		#endregion

		#region 抽象方法

		protected abstract Token CreateToken(string literal);

		#endregion
	}
}